/*
 * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "Appender.h"
#include <utility>
#include "Common.h"
#include "Util.h"

LogMessage::LogMessage(LogLevel _level, LogFilterType _type, std::string&& _text) : level(_level), type(_type), text(std::forward<std::string>(_text))
{
    mtime = time(nullptr);
}

std::string LogMessage::getTimeStr(time_t time)
{
    tm aTm;
    localtime_r(&time, &aTm);
    char buf[20];
    snprintf(buf, 20, "%04d-%02d-%02d_%02d:%02d:%02d", aTm.tm_year + 1900, aTm.tm_mon + 1, aTm.tm_mday, aTm.tm_hour, aTm.tm_min, aTm.tm_sec);
    return std::string(buf);
}

std::string LogMessage::getTimeStr()
{
    return getTimeStr(mtime);
}

Appender::Appender(uint8 _id, std::string _name, AppenderType _type /* = APPENDER_NONE*/, LogLevel _level /* = LOG_LEVEL_DISABLED */, AppenderFlags _flags /* = APPENDER_FLAGS_NONE */) :
    id(_id), name(std::move(_name)), type(_type), level(_level), flags(_flags)
{
}

Appender::~Appender() = default;

uint8 Appender::getId() const
{
    return id;
}

std::string const& Appender::getName() const
{
    return name;
}

AppenderType Appender::getType() const
{
    return type;
}

LogLevel Appender::getLogLevel() const
{
    return level;
}

AppenderFlags Appender::getFlags() const
{
    return flags;
}

void Appender::setLogLevel(LogLevel _level)
{
    level = _level;
}

void Appender::write(LogMessage* message)
{
    if (!level || level > message->level)
    {
        //fprintf(stderr, "Appender::write: Appender %s, Level %s. Msg %s Level %s Type %s WRONG LEVEL MASK\n", getName().c_str(), getLogLevelString(level), message->text.c_str(), getLogLevelString(message->level), getLogFilterTypeString(message->type)); // DEBUG - RemoveMe
        return;
    }

    message->prefix.clear();
    if (flags & APPENDER_FLAGS_PREFIX_TIMESTAMP)
        message->prefix.append(message->getTimeStr());

    if (flags & APPENDER_FLAGS_PREFIX_LOGLEVEL)
    {
        if (!message->prefix.empty())
            message->prefix.push_back(' ');

        char text[MAX_QUERY_LEN];
        snprintf(text, MAX_QUERY_LEN, "%-5s", getLogLevelString(message->level));
        message->prefix.append(text);
    }

    if (flags & APPENDER_FLAGS_PREFIX_LOGFILTERTYPE)
    {
        if (!message->prefix.empty())
            message->prefix.push_back(' ');

        char text[MAX_QUERY_LEN];
        snprintf(text, MAX_QUERY_LEN, "[%s]", getLogFilterTypeString(message->type));
        message->prefix.append(text);
    }

    if (!message->prefix.empty())
        message->prefix.push_back(' ');

    _write(message);
}

const char* Appender::getLogLevelString(LogLevel level)
{
    switch (level)
    {
    case LOG_LEVEL_FATAL:
        return "FATAL";
    case LOG_LEVEL_ERROR:
        return "ERROR";
    case LOG_LEVEL_WARN:
        return "WARN";
    case LOG_LEVEL_INFO:
        return "INFO";
    case LOG_LEVEL_DEBUG:
        return "DEBUG";
    case LOG_LEVEL_TRACE:
        return "TRACE";
    default:
        return "DISABLED";
    }
}

char const* Appender::getLogFilterTypeString(LogFilterType type)
{
    switch (type)
    {
    case LOG_FILTER_GENERAL:
        return "GENERAL";
    case LOG_FILTER_UNITS:
        return "UNITS";
    case LOG_FILTER_PETS:
        return "PETS";
    case LOG_FILTER_VEHICLES:
        return "VEHICLES";
    case LOG_FILTER_TSCR:
        return "TSCR";
    case LOG_FILTER_DATABASE_AI:
        return "DATABASE_AI";
    case LOG_FILTER_MAPSCRIPTS:
        return "MAPSCRIPTS";
    case LOG_FILTER_NETWORKIO:
        return "NETWORKIO";
    case LOG_FILTER_SPELLS_AURAS:
        return "SPELLS_AURAS";
    case LOG_FILTER_ACHIEVEMENTSYS:
        return "ACHIEVEMENTSYS";
    case LOG_FILTER_CONDITIONSYS:
        return "CONDITIONSYS";
    case LOG_FILTER_POOLSYS:
        return "POOLSYS";
    case LOG_FILTER_AUCTIONHOUSE:
        return "AUCTIONHOUSE";
    case LOG_FILTER_BATTLEGROUND:
        return "BATTLEGROUND";
    case LOG_FILTER_OUTDOORPVP:
        return "OUTDOORPVP";
    case LOG_FILTER_CHATSYS:
        return "CHATSYS";
    case LOG_FILTER_LFG:
        return "LFG";
    case LOG_FILTER_MAPS:
        return "MAPS";
    case LOG_FILTER_PLAYER:
        return "PLAYER";
    case LOG_FILTER_PLAYER_LOADING:
        return "PLAYER LOADING";
    case LOG_FILTER_PLAYER_ITEMS:
        return "PLAYER ITEMS";
    case LOG_FILTER_PLAYER_SKILLS:
        return "PLAYER SKILLS";
    case LOG_FILTER_PLAYER_CHATLOG:
        return "PLAYER CHATLOG";
    case LOG_FILTER_LOOT:
        return "LOOT";
    case LOG_FILTER_GUILD:
        return "GUILD";
    case LOG_FILTER_TRANSPORTS:
        return "TRANSPORTS";
    case LOG_FILTER_SQL:
        return "SQL";
    case LOG_FILTER_GMCOMMAND:
        return "GMCOMMAND";
    case LOG_FILTER_REMOTECOMMAND:
        return "REMOTECOMMAND";
    case LOG_FILTER_WARDEN:
        return "WARDEN";
    case LOG_FILTER_WORLDSERVER:
        return "WORLDSERVER";
    case LOG_FILTER_GAMEEVENTS:
        return "GAMEEVENTS";
    case LOG_FILTER_CALENDAR:
        return "CALENDAR";
    case LOG_FILTER_CHARACTER:
        return "CHARACTER";
    case LOG_FILTER_SQL_DRIVER:
        return "SQL DRIVER";
    case LOG_FILTER_SQL_DEV:
        return "SQL DEV";
    case LOG_FILTER_PLAYER_DUMP:
        return "PLAYER DUMP";
    case LOG_FILTER_BATTLEFIELD:
        return "BATTLEFIELD";
    case LOG_FILTER_SERVER_LOADING:
        return "SERVER LOADING";
    case LOG_FILTER_OPCODES:
        return "OPCODE";
    case LOG_FILTER_BATTLENET:
        return "BATTLENET";
    case LOG_FILTER_BNET_SESSION:
        return "BNET_SESSION";
    case LOG_FILTER_AREATRIGGER:
        return "AREATRIGGER";
    case LOG_FILTER_GOLD:
        return "GOLD";
    case LOG_FILTER_WORLD_QUEST:
        return "WORLD_QUEST";
    case LOG_FILTER_CHALLENGE:
        return "CHALLENGE";
    default:
        break;
    }
    return "???";
}
